package com.example.looptask;

import com.google.common.collect.Lists;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;

/**
 * 抽象的自定义任务类
 */
public abstract class AbstractCustomTask<T> {

    /**
     * 线程池大小
     */
    private final Integer poolSize = 8;

    /**
     * 数据拆分大小
     */
    private final Integer size;

    /**
     * 任务名称
     */
    private final String taskName;

    /**
     * 需要处理的数据集合
     */
    private final List<T> list;

    public AbstractCustomTask(String taskName, Integer size, List<T> list) {
        this.taskName = taskName;
        this.size = size;
        this.list = list;
    }

    /**
     * 任务执行入口
     */
    public void doExecute() {
        // 处理数据
        taskExecute();
        // 回收线程池资源
        TaskProcessUtil.releaseExecutors(taskName);
    }

    // 处理单个任务数据
    private void taskExecute() {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        // 将数据拆分
        List<List<T>> splitList = Lists.partition(list, size);
        final CountDownLatch latch = new CountDownLatch(splitList.size());

        // 并发处理拆分的数据，共用一个线程池
        for (final List<T> list : splitList) {
            ExecutorService executorService = TaskProcessUtil.getOrInitExecutors(taskName, poolSize);
            executorService.submit(() -> processData(list, latch));
        }

        try {
            latch.await();
        } catch (Exception e) {
            e.getStackTrace();
        }
    }

    /**
     * 处理数据
     */
    private void processData(List<T> list, CountDownLatch latch) {
        try {
            System.out.println("当前线程名称:" + Thread.currentThread().getName());
            this.doProcessData(list);
        } catch (Exception e) {
            e.getStackTrace();
        } finally {
            if (latch != null) {
                latch.countDown();
            }
        }
    }


    /**
     * 自定义任务方法,须重写
     */
    abstract void doProcessData(List<T> list);
}